﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Security.Cryptography.X509Certificates;
using AIMLbot;
using Matrix;
using Matrix.Xml;
using Matrix.Xmpp;
using Matrix.Xmpp.Client;
using Matrix.Xmpp.Register;
using Matrix.Xmpp.XData;
using ClientDemo.Settings;
using Presence=Matrix.Xmpp.Client.Presence;
using RosterItem=Matrix.Xmpp.Roster.RosterItem;
using Subscription=Matrix.Xmpp.Roster.Subscription;
using EventArgs=Matrix.EventArgs;

namespace ClientDemo
{
     
    public partial class FrmMain : Form
    {
        private readonly Dictionary<string, ListViewGroup>  _dictContactGroups = new Dictionary<string, ListViewGroup>();
        private readonly Dictionary<Jid, RosterItem>        _dictContats = new Dictionary<Jid, RosterItem>();

        private Settings.Settings _settings;
        private Login _login;

        public FrmMain()
        {
            InitializeComponent();

            SetLicense();

            RegisterCustomElements();
            InitSettings();
            InitContactList();
        }
        
       
        private static void RegisterCustomElements()
        {
            Factory.RegisterElement<Settings.Settings>  ("ag-software:settings", "Settings");
            Factory.RegisterElement<Login>              ("ag-software:settings", "Login");
        }

        private void InitSettings()
        {
            _settings = Util.LoadSettings();
            if (_settings.Login == null)
                _settings.Login = new Login();
            
            _login = _settings.Login;
            
            if (_login != null)
            {
                if (!string.IsNullOrEmpty(_login.User))
                    txtUsername.Text = _login.User;
            
                if (!string.IsNullOrEmpty(_login.Password))
                    txtPassword.Text    = _login.Password;
            }
        }

        /// <summary>
        /// Sets the license and activate the evaluation.
        /// </summary>
        private static void SetLicense()
        {
            /*
            const string LIC =@"your personal licence ley";
            Matrix.License.LicenseManager.SetLicense(LIC);
            */
        }
       
        private void cmdConnect_Click(object sender, System.EventArgs e)
        {
            xmppClient.SetUsername(txtUsername.Text);
            xmppClient.SetXmppDomain("gmail.com");
            xmppClient.Password = txtPassword.Text;
            
            xmppClient.Status = "ready for chat";
            xmppClient.Show = Matrix.Xmpp.Show.chat;

            // set settings
            _login.User = txtUsername.Text;
            _login.Password = txtPassword.Text;

            // you can also disable SRV lookups and specify the sever hostname manual
            //xmppClient.ResolveSrvRecords = false;
            //xmppClient.Hostname = "192.168.1.106";

            xmppClient.Open();
        }

        private void xmppClient_OnError(object sender, ExceptionEventArgs e)
        {
        }

        private void xmppClient_OnLogin(object sender, Matrix.EventArgs e)
        {
        }

        private void DisplayEvent(string ev)
        {
        }

        private void xmppClient_OnBind(object sender, JidEventArgs e)
        {
        }

        private void xmppClient_OnClose(object sender, Matrix.EventArgs e)
        {
            listContacts.Items.Clear();
        }

        private void xmppClient_OnRosterStart(object sender, Matrix.EventArgs e)
        {

        }

        private void xmppClient_OnRosterEnd(object sender, Matrix.EventArgs e)
        {
        }

        private void xmppClient_OnRosterItem(object sender, Matrix.Xmpp.Roster.RosterEventArgs e)
        {
            if (e.RosterItem.Subscription != Subscription.remove)
            {
                // set a default group name
                string groupname = "未分组联系人";

                // id the contact has groups get the 1st group. In this example we don't support multiple or nested groups
                // for contacts, but XMPP has support for this.
                if (e.RosterItem.HasGroups)
                    groupname = e.RosterItem.GetGroups()[0];

                if (!_dictContactGroups.ContainsKey(groupname))
                {
                    var newGroup = new ListViewGroup(groupname);
                    _dictContactGroups.Add(groupname, newGroup);
                    listContacts.Groups.Add(newGroup);
                }

                var listGroup = _dictContactGroups[groupname];

                // contact already exists, this is a contact update
                if (_dictContats.ContainsKey(e.RosterItem.Jid))
                {
                    listContacts.Items.RemoveByKey(e.RosterItem.Jid);
                }

                //var newItem = new ListViewItem(e.RosterItem.Jid, listGroup) {Name = e.RosterItem.Jid};
                var newItem = new RosterListViewItem(e.RosterItem.Name ?? e.RosterItem.Jid, 0, listGroup)
                                  {Name = e.RosterItem.Jid.Bare};
                newItem.SubItems.AddRange(new[] {"", ""});
                
              
                listContacts.Items.Add(newItem);
            }
        }

        private static int GetRosterImageIndex(Presence pres)
        {
            if (pres.Type == PresenceType.unavailable)
                return 0;
           
            switch (pres.Show)
            {
                case Matrix.Xmpp.Show.chat:
                    return 1;
                case Matrix.Xmpp.Show.away:
                    return 2;
                case Matrix.Xmpp.Show.xa:
                    return 2;
                case Matrix.Xmpp.Show.dnd:
                    return 3;
                default:
                    return 1;
            }
        }

        private void xmppClient_OnPresence(object sender, PresenceEventArgs e)
        {
            if (e.Presence.Type == PresenceType.subscribe)
            {
                
            }
            else if (e.Presence.Type == PresenceType.subscribed)
            {

            }
            else if (e.Presence.Type == PresenceType.unsubscribe)
            {

            }
            else if (e.Presence.Type == PresenceType.unsubscribed)
            {

            }
            else
            {
                var item = listContacts.Items[e.Presence.From.Bare] as RosterListViewItem;
                if (item != null)
                {
                    item.ImageIndex = GetRosterImageIndex(e.Presence);
                    string resource = e.Presence.From.Resource;
                    if (e.Presence.Type != PresenceType.unavailable)
                    {
                        if (!item.Resources.Contains(resource))
                            item.Resources.Add(resource);
                    }
                    else
                    {
                        if (item.Resources.Contains(resource))
                            item.Resources.Remove(resource);
                    }
                }
            }
        }

        private void xmppClient_OnIq(object sender, IqEventArgs e)
        {
        }

        private void xmppClient_OnMessage(object sender, MessageEventArgs e)
        {
            // we ignore GroupChat Messages here
            if (e.Message.Type == MessageType.groupchat)
                return;

            if (e.Message.Type == MessageType.error)
            {
                //Handle errors here
                // we dont handle them in this example
                return;
            }
            if (e.Message.Body != null)
            {
                if (!Util.ChatForms.ContainsKey(e.Message.From.Bare))
                {
                    //get nickname from the roster listview
                    string nick = e.Message.From.Bare;
                    var item = listContacts.Items[e.Message.From.Bare];
                    if (item != null)
                        nick = item.Text;
                    
                    FrmChat chatFrm0 = new FrmChat(e.Message.From, xmppClient, nick);
                    chatFrm0.Dock = DockStyle.Fill;
                    initialLize_chatPage(chatFrm0, nick);
                    chatFrm0.IncomingMessage(e.Message);
                }
            }
        }

        private void xmppClient_OnValidateCertificate(object sender, CertificateEventArgs e)
        {
            // always accept cert
             e.AcceptCertificate = true;

            // or let the user validate the certificate
            //ValidateCertificate(e);
        }
        
        /*private void ValidateCertificate(CertificateEventArgs e)
        {
            //DisplayEvent("OnValidateCertificate");
           

            if (e.SslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
            {
                e.AcceptCertificate = true;
            }
            else
            {
                X509Certificate2UI.DisplayCertificate(new X509Certificate2(e.Certificate));
                if (MessageBox.Show("Accept Certificate", "Certificate", MessageBoxButtons.YesNo) == DialogResult.Yes)
                    e.AcceptCertificate = true;
                else
                    e.AcceptCertificate = false;                
            }
        }
       */

        private void xmppClient_OnBeforeSasl(object sender, Matrix.Xmpp.Sasl.SaslEventArgs e)
        {
            /*
            with the following code you can disable the SASL automatic and manual specify a mechanism.
            
             * e.Auto = false;
            e.SaslMechanism = Matrix.Xmpp.Sasl.SaslMechanism.PLAIN;
            */

            /*
            // X_FACEBOOK_PLATFORM Facebook Auth example
            e.Auto = false;
            e.SaslMechanism = Matrix.Xmpp.Sasl.SaslMechanism.X_FACEBOOK_PLATFORM;

            const string APPLICATION_KEY = "12345678901234567890";
            const string SECRET_KEY = "98765432109876543210";
            e.SaslProperties = new Matrix.Xmpp.Sasl.Processor.Facebook.FacebookProperties
                                   {
                                       ApiKey = APPLICATION_KEY,
                                       ApiSecret = SECRET_KEY,
                                       SessionKey = "session_key_from_facebook_api"
                                   };
            */
        }

        private void xmppClient_OnAuthError(object sender, Matrix.Xmpp.Sasl.SaslEventArgs e)
        {
            xmppClient.Close();
        }
        
        /// <summary>
        /// Inits the contact list.
        /// </summary>
        private void InitContactList()
        {
            listContacts.Clear();

            listContacts.Columns.Add("Name", 100, HorizontalAlignment.Left);
            listContacts.Columns.Add("Status", 75, HorizontalAlignment.Left);
            listContacts.Columns.Add("Resource", 75, HorizontalAlignment.Left);

            listContacts.LargeImageList = ilstStatus;
        }

        private void xmppClient_OnStreamError(object sender, StreamErrorEventArgs e)
        {
        }

        private void frmMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            Util.SaveSettings(_settings);
        }

        private void chatToolStripMenuItem_Click(object sender, System.EventArgs e)
        {
            if (listContacts.SelectedItems.Count > 0)
            {
                var item = listContacts.SelectedItems[0];
                if (!Util.ChatForms.ContainsKey(item.Name))
                {
                    FrmChat chatFrm = new FrmChat(item.Name, xmppClient, item.Text);
                    chatFrm.Dock = DockStyle.Fill;
                    initialLize_chatPage(chatFrm, item.Name);
                }
            }
        }

        private void initialLize_chatPage(FrmChat chatFrm, string nickname)
        {
            System.Windows.Forms.TabPage tabPage = new System.Windows.Forms.TabPage();
            //
            //tabPage
            //
            tabPage.Controls.Add(chatFrm);
            tabPage.Name = nickname;
            tabPage.Text = "和" + nickname + "的聊天";
            //
            this.tabControl2.Controls.Add(tabPage);
            this.tabControl2.SelectedTab = tabPage;
            this.listView1.Controls.Add(chatFrm.myAIML);
        }

        private void listContacts_MouseUp(object sender, MouseEventArgs e)
        {
            //Check if right clicked on a ListView Item
            if ((listContacts.SelectedItems.Count != 0) && (e.Button == MouseButtons.Right))
            {
                // dynamically adjust context menu with resources.
               var item = listContacts.SelectedItems[0] as RosterListViewItem;
                // show context menu
                ctxMenuRoster.Show(Cursor.Position);
            }
        }

        private void tabControl2_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            TabControl tabControl2 = (TabControl)sender;
            Point pt = new Point(e.X, e.Y);

            for (int i = 0; i < tabControl2.TabCount; i++)
            {
                Rectangle recTab = tabControl2.GetTabRect(i);
                if (recTab.Contains(pt))
                {
                    TabPage seltab = this.tabControl2.SelectedTab;
                    int seltabindex = this.tabControl2.SelectedIndex;
                    if (seltabindex == 0) return;
                    tabControl2.Controls.Remove(seltab);
                    Util.ChatForms.Remove(seltab.Name);
                    seltab.Controls.Clear();
                    seltab.Dispose();
                    tabControl2.SelectTab(seltabindex - 1);
                    if (this.tabControl2.TabCount == 1) this.listView1.Controls.Clear(); 
                    return;
                }
            }
        }

        private void xmppClient_OnRegisterInformation(object sender, RegisterEventArgs e)
        {
            e.Register.RemoveAll<Data>();
            
            e.Register.Username = xmppClient.Username;
            e.Register.Password = xmppClient.Password;
        }

        private void xmppClient_OnRegister(object sender, EventArgs e)
        {

        }

        private void xmppClient_OnRegisterError(object sender, IqEventArgs e)
        {
            xmppClient.Close();
        }

        private void presenceManager_OnSubscribe(object sender, PresenceEventArgs e)
        {
            presenceManager.ApproveSubscriptionRequest(e.Presence.From);
            //presenceManager.DenySubscriptionRequest(e.Presence.From);
        }

        private void 退出ToolStripMenuItem_Click(object sender, System.EventArgs e)
        {
            this.Close();
        }
    }
}